package com.sad.jetpack.v1.datamodel.api.extension.client.socket.ipc;


import java.io.InputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.text.NumberFormat;

public class DefaultIPCChatMessenger implements IPCChatMessenger{
    public final static int NEXT_DATA_SIZE_MARK_LENGTH =16;
    private Socket socket;

    public DefaultIPCChatMessenger(Socket socket) {
        this.socket = socket;
    }

    @Override
    public byte[] syncSend(byte[] data, int cacheSize,boolean read) throws Exception {
        IPCStreamUtils.writeBytes(socket,formatDataFutureSizeStr(data.length,NEXT_DATA_SIZE_MARK_LENGTH).getBytes(StandardCharsets.UTF_8));

        if (read){
            boolean we=IPCStreamUtils.writeBytes(socket, data);
            if (we){
                return syncReceive(cacheSize);
            }
        }
        else {
            IPCStreamUtils.writeBytes(socket, data);
        }
        return null;
    }

    @Override
    public byte[] syncSend(InputStream outSideInputStream, int cacheSize, int futureSize,boolean read) throws Exception {
        return syncSend(outSideInputStream,cacheSize,futureSize,read,null);
    }

    @Override
    public byte[] syncSend(InputStream outSideInputStream, int cacheSize, int futureSize, boolean read, IPCStreamUtils.InputStreamReadingListener proxyListener) throws Exception {
        IPCStreamUtils.writeBytes(socket,formatDataFutureSizeStr(futureSize,NEXT_DATA_SIZE_MARK_LENGTH).getBytes(StandardCharsets.UTF_8));
        IPCStreamUtils.handleInputStream(outSideInputStream, cacheSize, futureSize, new IPCStreamUtils.InputStreamReadingListener() {
            @Override
            public void onLoopReading(byte[] bytes, int readIndex, int futureSize) throws Exception {
                boolean ws=IPCStreamUtils.writeBytes(socket,bytes);
                if (!ws){
                    throw new Exception("socket outstream writing sth from inputstream failed !!!");
                }
                if (proxyListener!=null){
                    proxyListener.onLoopReading(bytes,readIndex,futureSize);
                }
            }
        });
        if (read){
            return syncReceive(cacheSize);
        }
        return null;
    }


    @Override
    public byte[] syncReceive(int cacheSize) throws Exception {
        InputStream inputStream=socket.getInputStream();
        int nextSize=nextDataFutureSize();
        if (nextSize>0){
            byte[] result=IPCStreamUtils.readBytes(inputStream,cacheSize==-1?nextSize:cacheSize,nextSize);
            return result;
        }
        return null;
    }
    @Override
    public void syncReceive(int cacheSize, IPCStreamUtils.InputStreamReadingListener readingListener) throws Exception {
        InputStream inputStream=socket.getInputStream();
        int nextSize=nextDataFutureSize();
        if (nextSize>0){
            IPCStreamUtils.handleInputStream(inputStream,cacheSize==-1?nextSize:cacheSize,nextSize,readingListener);
        }
    }

    private String formatDataFutureSizeStr(int size,int markSize){
        NumberFormat nbf = NumberFormat.getNumberInstance();
        nbf.setMinimumIntegerDigits(markSize);
        nbf.setGroupingUsed(false);
        String s=nbf.format(size);
        return s;
    }
    @Override
    public int nextDataFutureSize() throws Exception {
        byte[] sm= IPCStreamUtils.readBytes(socket.getInputStream(), NEXT_DATA_SIZE_MARK_LENGTH, NEXT_DATA_SIZE_MARK_LENGTH);
        String smStr=new String(sm);
        int size=Integer.valueOf(smStr);
        return size;
    }
}
